﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SockLib.Device
{
    public class ModbusMsg
    {
        /// <summary>
        /// <para>目标gprs编号</para>
        /// <para>发送数据时，gprs编号：-1表示群发，当前组号下所有节点设备能够接收到数据</para>
        /// <para>接收数据时，收到的GPRS编号</para>
        /// </summary>
        public string socket_id { get; set; }

        /// <summary>
        /// 设备编号
        /// </summary>
        public int device_id { get; set; }

        /// <summary>
        /// 设备功能码
        /// </summary>
        public int device_cmd { get; set; }

        /// <summary>
        /// 是否低位在前
        /// </summary>
        public bool IsLowBitFirst { get; set; }
    }


    /// <summary>
    /// modbus读取数据
    /// </summary>
    class ModbusSend : ModbusMsg
    {
        /// <summary>
        /// 开始读取(写入)的寄存器
        /// </summary>
        public int device_startreg { get; set; }

        /// <summary>
        /// <para>读取寄存器个数</para>
        /// <para>读寄存器时写入寄存器数组等于Null</para>
        /// </summary>
        public int device_reglength { get; set; }

        /// <summary>
        /// <para>写入寄存器的数组</para>
        /// <para>写入寄存器数组时，读取寄存器个数等于0</para>
        /// </summary>
        public byte[] device_WriteData { get; set; }

        /// <summary>
        /// 无线模块ID,0代表透传
        /// </summary>
        public int  wireless_id { get; set; }

        /// <summary>
        /// 设备类型用来解析modbus数据
        /// </summary>
        public int Device_type { get; set; }

    }

    /// <summary>
    /// modbus数据注册类
    /// </summary>
    class ModbusReg
    {
        /// <summary>
        /// 注册编号
        /// </summary>
        public string reg_id { get; set; }

        /// <summary>
        /// 注册手机号
        /// </summary>
        public string phone { get; set; }

        /// <summary>
        /// 设备类型,用何种解码方法
        /// </summary>
        public int devicetype { get; set; }

        /// <summary>
        /// 验证字符串
        /// </summary>
        public string user_key { get; set; }
    }

    /// <summary>
    /// modbus数据返回类
    /// </summary>
    class ModbusData : ModbusMsg
    {
        /// <summary>
        /// 设备类型描述
        /// </summary>
        public string Dtype { get; set; }

        /// <summary>
        /// 设备类型代号
        /// </summary>
        public int Did { get; set; }

        /// <summary>
        /// 进行的是何种操作，比如开关阀等，每种操作做一种标识
        /// </summary>
        public int DOper { get; set; }

        /// <summary>
        /// 解析后的数据
        /// </summary>
        public Dictionary<string, object> data { get; set; }

        /// <summary>
        /// 收到的原始数据
        /// </summary>
        public byte[] recdata { get; set; }
    }

    public class CRC
    {
        /// <summary>
        /// CRC-CCITT (Kermit)算法
        /// </summary>
        /// <param name="bufData">需要计算的数据</param>
        /// <param name="IsLowBitFirs">是否高位在前，true是，false否</param>
        /// <returns></returns>
        public static byte[] GetCRC(byte[] bufData,bool  IsLowBitFirs)
        {
            ushort CRC = 0XFFFF;
            for (int i = 0; i < bufData.Length; i++)
            {
                CRC ^= bufData[i];
                for (int j = 0; j < 8; j++)
                {
                    if ((CRC & 0x0001) != 0)
                    {
                        CRC >>= 1;
                        CRC ^= 0xA001;
                    }
                    else
                    {
                        CRC >>= 1;
                    }
                }
            }
            if(IsLowBitFirs )
            return System.BitConverter.GetBytes(CRC);
            else 
            return new byte[] { (byte)(CRC / 256), (byte)(CRC % 256) };
        }

        /// <summary>
        /// 检查CRC校验是否相等
        /// </summary>
        /// <param name="bufData">要检测的byte[],最后两位必须是CRC的高位和低位</param>
        /// <param name="IsLowBitFirs">CRC校验是否是低位在前,默认低位在后</param>
        /// <returns></returns>
        public static bool CheckCrc(byte[] bufData, bool IsLowBitFirs=false )
        {
            List<byte> data = new List<byte>();
            data.AddRange(bufData);
            data.RemoveAt(data.Count - 1);  //移除CRC校验低位
            data.RemoveAt(data.Count - 1);  //移除CRC校验高位
            byte[] crc = GetCRC(data.ToArray(),   IsLowBitFirs);
            if (bufData[bufData.Length - 1] == crc[1] && bufData[bufData.Length - 2] == crc[0])
                return true;
            else
                return false;
        }

    }

}


